1. Connecting Express Server with Axios (vite)
Now in the previous chapter we created a backend with the json data 4.Setting up Backend
so now we create a normal vite project and in app.js we write a code to get the json data from the backend to display on the webpage
"use client"
import { useEffect, useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import axios from 'axios'
function App() {
const [jokes, setjokes] = useState([]);
useEffect(() => {
axios.get('http://localhost:3000/jokes')
.then((response) => {
setjokes(response.data)
})
.catch((error) => {
console.log(error)
})
})
return (
<>
<h1> Jokes page </h1>
<p>{jokes.length}</p>
{
jokes.map((joke, index) => {
<div key={joke.id}>
<h3>{joke.title}</h3>
<p>{joke.cotent}</p>
</div>
})
}
</>
)
}
export default App
we used axios for the fetching the data from backend it is a normal package to get data to learn more read this note 5. Theory Axios Read Only
But when we run this front end code we get this error
Access to XMLHttpRequest at 'http://localhost:3000/jokes' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This error means the server at http://localhost:3000 is not allowing requests from the origin http://localhost:5173 due to CORS (Cross-Origin Resource Sharing) restrictions, as it lacks the Access-Control-Allow-Origin header.
What is CORS?
CORS (Cross-Origin Resource Sharing) is a security feature implemented by web browsers that:
- Prevents malicious websites from making unauthorized requests to different domains
- Controls access to resources between different origins
- Protects users from potential security vulnerabilities
- CORS must be enabled on the backend to allow frontend requests
- The
corsmiddleware should be added before defining routes
Example Scenario
A web page hosted on http://localhost:3000 (frontend) tries to fetch data from http://localhost:5000 (backend). The browser will:
- Check if the backend server allows requests from the frontend origin
- Block the request if proper CORS headers are not present
Implementation Guide
1. Installation
Install required packages using npm:
npm i dotenv cors express
2. Backend Setup (Using Express)
server.js
// Using ES Modules
import express from 'express';
import dotenv from 'dotenv';
import cors from 'cors';
// Alternative using Common JS:
// const express = require("express")
// const dotenv = require("dotenv").config();
// const cors = require("cors");
const app = express();
dotenv.config();
const port = process.env.PORT;
// Enable CORS for all routes
app.use(cors());
// Routes
app.get("/", (req, res) => {
res.send("hello");
});
app.get("/api/jokes", (req, res) => {
const jokes = [
{
id: 1,
title: "1st Joke",
content: "Why don't skeletons fight each other? They don't have the guts."
},
{
id: 2,
title: "2nd Joke",
content: "Why don’t some couples go to the gym? Because some relationships don’t work out."
},
{
id: 3,
title: "3rd Joke",
content: "Why did the scarecrow win an award? Because he was outstanding in his field."
},
{
id: 4,
title: "4th Joke",
content: "I told my wife she was drawing her eyebrows too high. She looked surprised."
},
{
id: 5,
title: "5th Joke",
content: "I’m reading a book about anti-gravity. It’s impossible to put down."
}
];
res.send(jokes);
});
// Start server
app.listen(port, () => {
console.log(`Port is running on ${port}`);
});
3. dotenv
-
.envfiles let you store sensitive information (like API keys, database passwords, configuration settings) separate from your code, helping keep your secrets secure and making it easier to manage different settings between development and production environments. -
The
dotenvpackage loads these environment variables from your.envfile intoprocess.envin your Node.js application, making them accessible throughout your code without exposing them in your repository.Create a .env file in your backend project folder
PORT = 3000
4. Frontend
App.js
import React, {useState, useEffect} from 'react';
import axios from 'axios';
function App(){
const [data, setData] = useState([]);
const [error, setError] = useState(null);
useEffect(()=>{
axios.get('/api/jokes')
.then((response) => {
setData(response.data)
})
.catch((err) => {
setError(err);
console.log(err);
})
},[])
//as this is asynchronous it will take time to fetch data from api so we run it in another useEffect so whenver the date comes/update it fill fetch directly and print in the console
useEffect(()=>{
console.log(data)
}, [data])
return (
<div>
<ul>
{data.map((joke)=> (
<li key={joke.id}>
<p>Title: {joke.title}</p>
<p>Content: {joke.content}</p>
</li>
))}
</ul>
</div>
)
}
export default App;
5. Frontend Proxy Setup
In Vite, proxying is used to handle requests that are made to a different server or backend during development. When you're building a full-stack application, typically you will have your frontend (React app) running on one server (e.g., Vite's development server on localhost:5173) and your backend (e.g., an Express API) running on another server (e.g., localhost:3000).
Why We Use Proxy in Vite:
-
Cross-Origin Resource Sharing (CORS) Issues: When your frontend makes requests to a different port (or domain) than the one it is served on, the browser will block the request due to CORS restrictions. The proxy in the Vite config allows the frontend to make requests to the backend without triggering CORS errors.
-
Simplify API Calls: Without a proxy, you would need to specify the full URL (
http://localhost:3000/api) in all your API requests. With the proxy, you can make requests like/api/..., and Vite will internally forward them to the appropriate backend server (http://localhost:3000/api/...).
vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
server: {
proxy:{
'/api': 'http://localhost:3000',
},
},
plugins: [react()],
})